package cn.mill.core.utils;

import java.lang.reflect.Type;
import java.net.URI;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.mill.common.Node;
import cn.mill.common.Protocol;
import cn.mill.common.Spell;
import cn.mill.common.Strategy;
import cn.mill.core.Constants;
import cn.mill.core.modem.BaseSpell;
import cn.mill.core.modem.BooleanSpell;
import cn.mill.core.modem.DateSpell;
import cn.mill.core.modem.JavaBeanSpell;
import cn.mill.core.modem.ListArraySpell;
import cn.mill.core.modem.MapSpell;
import cn.mill.core.modem.NumberSpell;
import cn.mill.core.modem.ResultSpell;
import cn.mill.core.node.DefaultNode;

public class ConfigBuilder {
	private static Logger logger = LoggerFactory.getLogger(ConfigBuilder.class);
	
	public Map<String, Node> NodeBuilder() {
		Map<String, Node> index = new HashMap<String, Node>();
		PropertiesUtil p = new PropertiesUtil();
		Properties properties = p.getProperties();
		if (properties != null) {
			Set<Map.Entry<Object, Object>> sets = properties.entrySet();
			try {
				for (Entry<?, ?> e : sets) {
					String key = (String) e.getKey();
					if (NormUtil.isNotEmpty(key) && key.startsWith(Constants.NODE)) {
						logger.debug("node:[" + e.getValue() + "]");
						index.put(key, this.NodeBuilder(new URI((String) e.getValue())));
					}
				}
			} catch (Exception e) {
				logger.error("NodeBuilder", e);
			}
		}
		return index;
	}
	
	public Node NodeBuilder(URI uri) {
		if (uri != null) {
			DefaultNode n = new DefaultNode();
			String[] userinfo = this.splic(uri.getUserInfo());
			n.setHost(uri.getHost());
			n.setPath(uri.getPath());
			n.setPort(uri.getPort());
			n.setProtocol(uri.getScheme());
			n.setUsername((userinfo != null && userinfo.length > 1) ? userinfo[0] : "");
			n.setPassword((userinfo != null && userinfo.length > 1) ? userinfo[1] : "");
			return n;
		}
		return null;
	}
	
	@SuppressWarnings("rawtypes")
	public Map<String, Protocol<?, ?>> ProtocolBuilder() {
		Map<String, Protocol<?, ?>> index = new HashMap<String, Protocol<?, ?>>();
		ServiceLoader<Protocol> list = SpiUtil.loadSPI(Protocol.class);
		for (Protocol p : list) {
			String name = SpiUtil.getSPIAnnotation(p).value();
			logger.debug("load Protocol SPI==> " + name + ":" + p.getClass().getName());
			index.put(name, p);
		}
		return index;
	}
	
	@SuppressWarnings("rawtypes")
	public Map<String, Strategy<?, ?>> StrategyBuilder() {
		Map<String, Strategy<?, ?>> index = new HashMap<String, Strategy<?, ?>>();
		ServiceLoader<Strategy> list = SpiUtil.loadSPI(Strategy.class);
		for (Strategy s : list) {
			String name = SpiUtil.getSPIAnnotation(s).value();
			logger.debug("load Strategy SPI==> " + name + ":" + s.getClass().getName());
			index.put(name, s);
		}
		return index;
	}
	
	public Map<Type, Spell> SpellBuilder() {
		Map<Type, Spell> index = new HashMap<Type, Spell>();
		index.put(Integer.TYPE, NumberSpell.INSTANCE);/* 1 */
		index.put(Integer.class, NumberSpell.INSTANCE);/* 2 */
		index.put(Long.TYPE, NumberSpell.INSTANCE);/* 3 */
		index.put(Long.class, NumberSpell.INSTANCE);/* 4 */
		index.put(Short.TYPE, NumberSpell.INSTANCE);/* 5 */
		index.put(Short.class, NumberSpell.INSTANCE);/* 6 */
		index.put(Float.TYPE, NumberSpell.INSTANCE);/* 7 */
		index.put(Float.class, NumberSpell.INSTANCE);/* 8 */
		index.put(Double.TYPE, NumberSpell.INSTANCE);/* 9 */
		index.put(Double.class, NumberSpell.INSTANCE);/* 10 */
		index.put(String.class, BaseSpell.INSTANCE);
		index.put(Boolean.class, BooleanSpell.INSTANCE);
		index.put(Boolean.TYPE, BooleanSpell.INSTANCE);
		index.put(Date.class, DateSpell.INSTANCE);
		index.put(java.sql.Date.class, DateSpell.INSTANCE);
		index.put(Timestamp.class, DateSpell.INSTANCE);
		index.put(java.sql.Date.class, DateSpell.INSTANCE);
		index.put(Map.class, MapSpell.INSTANCE);
		index.put(List.class, ListArraySpell.INSTANCE);
		index.put(Object.class, JavaBeanSpell.INSTANCE);
		index.put(cn.mill.core.Result.class, ResultSpell.INSTANCE);
		logger.debug("load Spell Ok ");
		return index;
	}
	
	private String[] splic(String str) {
		if (NormUtil.isNotEmpty(str)) {
			return str.split(":");
		}
		return null;
	}
}